package com.htfyun.eink.pw.draw.pen.epd;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.htfyun.eink.pw.bitmap.bitmap_recycle.BitmapPool;
import com.htfyun.eink.pw.bitmap.bitmap_recycle.LruBitmapPool;
import com.htfyun.eink.pw.configs.PWConfig;
import com.htfyun.eink.pw.core.ctrl.PWCoreHelper;
import com.htfyun.eink.pw.draw.IPWDrawPath;
import com.htfyun.eink.pw.draw.IPWDrawProperty;
import com.htfyun.eink.pw.draw.cache.IPathCache;
import com.htfyun.eink.pw.draw.pen.IPenWriter;
import com.htfyun.eink.pw.draw.pen.PenDrawPointerResultEnums;
import com.htfyun.eink.pw.draw.pen.epd.charcoal.BitmapData;
import com.htfyun.eink.pw.draw.pen.epd.charcoal.CharcoalManager;
import com.htfyun.eink.pw.draw.pen.epd.data.NeoRenderPoint;
import com.htfyun.eink.pw.draw.pointer.PWPointer;
import com.htfyun.eink.pw.draw.pointer.PWPointerActionEnums;
import com.htfyun.eink.pw.utils.PWUtils;

import java.nio.IntBuffer;
import java.util.List;
import java.util.Map;

public class PenEPDCharcoal implements IPenWriter {
    public static final String PEN_ID = PenEPDCharcoal.class.getSimpleName();

    protected final Rect rectOfUpdatePW = new Rect();

    private final CharcoalManager manager;

    private int lastPointIndex = 0;

    private final BitmapPool bitmapPool = new LruBitmapPool(50 * 1024 * 1024);

    public PenEPDCharcoal() {
        this.manager = new CharcoalManager();
    }

    @NonNull
    @Override
    public PenDrawPointerResultEnums drawPointer(@NonNull IPWDrawPath draw, @NonNull PWPointer pointer) {
        manager.setStrokeWidth(draw.getPaintConfig().strokeWidth);

        PWPointerActionEnums actionEnums = pointer.toPWPointerActionEnums();

        switch (actionEnums) {
            case DOWN:
                manager.onDown(pointer);
                break;
            case MOVE:
                manager.onMove(pointer);
                break;
            case UP:
                manager.onUp(pointer);
                break;
            default:
                break;
        }

        PenDrawPointerResultEnums resultEnums = handle(draw);

        if (actionEnums == PWPointerActionEnums.UP) {
            manager.clear();
            lastPointIndex = 0;
        }
        return resultEnums;
    }

    private PenDrawPointerResultEnums handle(@NonNull IPWDrawPath draw) {
        List<NeoRenderPoint> renderPoints = manager.getRenderPoints();
        if (renderPoints.size() == 0 || lastPointIndex >= renderPoints.size()) {
            return PenDrawPointerResultEnums.NONE;
        }

        NeoRenderPoint lastPoint = renderPoints.get(lastPointIndex);

        Map<Integer, BitmapData> tableMap = manager.getPointTableMap();

        if (draw instanceof IPWDrawProperty) {
            IPWDrawProperty drawProperty = (IPWDrawProperty) draw;
            Canvas canvas = drawProperty.getCanvasPW();

            for (int index = lastPointIndex; index < renderPoints.size(); index++) {
                NeoRenderPoint pointer = renderPoints.get(index);

                BitmapData data = tableMap.get(lastPoint.bitmapIndex);
                if (data == null) {
                    continue;
                }

                Bitmap bitmap = bitmapPool.get(data.width, data.height, Bitmap.Config.ARGB_8888);

                IntBuffer pixelsArray = IntBuffer.allocate(data.width * data.height);
                for (int[] d : data.data) {
                    pixelsArray.put(d);
                }
                pixelsArray.rewind();
                bitmap.copyPixelsFromBuffer(pixelsArray);

                canvas.drawBitmap(bitmap, pointer.x, pointer.y, null);

                rectOfUpdatePW.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
                rectOfUpdatePW.offset(PWUtils.toCeil(pointer.x), PWUtils.toCeil(pointer.y));

                PWCoreHelper.postRectForPw(rectOfUpdatePW,
                        PWConfig.Instance.configFreshMode.getPWDisplayMode(),
                        PWConfig.Instance.configFreshMode.getPWA2Gate());

                bitmapPool.put(bitmap);
            }
        }

        lastPointIndex = renderPoints.size() - 1;
        if (lastPointIndex < 0) {
            lastPointIndex = 0;
        }

        return PenDrawPointerResultEnums.NONE;
    }

    @NonNull
    @Override
    public Rect getDirty() {
        return rectOfUpdatePW;
    }

    @NonNull
    @Override
    public String getPenId() {
        return PEN_ID;
    }


    @Nullable
    @Override
    public IPathCache getPathCache() {
        return null;
    }
}
